/**
 * 
 */
package edu.whu.rose.clock.ssql.statistic;

import com.sleepycat.je.Cursor;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;

import edu.whu.rose.clock.ssql.binding.SubGraphBinding;
import edu.whu.rose.clock.ssql.graph.RRadiusSubGraph;
import edu.whu.rose.clock.ssql.graph.SubGraphDB;
import edu.whu.rose.clock.ssql.util.ExpandableIntArray;

public class GraphStatistic {

	public int n;
	public int m;
	public ExpandableIntArray sizes;
	public double avgSize;
	public double theoSize;
	
	public GraphStatistic() {
		sizes = new ExpandableIntArray();
	}
	
	public static void main(String[] args) {
		GraphStatistic gs = new GraphStatistic();
		gs.statDataGraph(198467, 620368);
		gs.statSubgraphSize("dbEnv_subgraph");
	}
	
	public void statSubgraphSize(String dbEnv) {
		// initialize the database storing all subgraphs
		SubGraphDB sgdb = new SubGraphDB(dbEnv);
		if (!(sgdb.initEnv() && sgdb.openDB())) {
			return;
		}
		
		// iteratively visit each subgraph
		try {
			Cursor cursor = sgdb.getCursorOfSubgraphs();
			DatabaseEntry key = new DatabaseEntry();
			DatabaseEntry value = new DatabaseEntry();
			while (cursor.getNext(key, value, LockMode.DEFAULT) == OperationStatus.SUCCESS) {
				SubGraphBinding sgb = new SubGraphBinding();
				RRadiusSubGraph rrsg = (RRadiusSubGraph)sgb.entryToObject(value);
				sizes.add(rrsg.getVertexNumber());
			}
		}
		catch (DatabaseException ex) {
			ex.printStackTrace();
		}
		
		// statistic
		int sum = 0;
		int max = 0;
		int min = sizes.get(0);
		for (int i = 0; i < sizes.getSize(); i++) {
			sum += sizes.get(i);
			if (sizes.get(i) > max) {
				max = sizes.get(i);
			}
			if (sizes.get(i) < min) {
				min = sizes.get(i);
			}
		}
		avgSize = (double) sum / (double) sizes.getSize();
		double newAvgDeg = ((double) m + 2 * (2 * (double) (sum - n) - sizes.getSize())) / (double) sum;
		double newTheoSize = 1.0D + newAvgDeg + Math.pow(newAvgDeg, 2);
		int a = 0;
		int b = 0;
		int c = 0;
		int d = 0;
		int e = 0;
		int f = 0;
		int g = 0;
		int h = 0;
		for (int i = 0; i < sizes.getSize(); i++) {
			if (sizes.get(i) < ((double) m / (double) n)) {
				g++;
			}
			else if (sizes.get(i) < avgSize / 4) {
				h++;
			}
			else if (sizes.get(i) < avgSize / 2) {
				a++;
			}
			else if (sizes.get(i) < avgSize) {
				b++;
			}
			else if (sizes.get(i) < (avgSize * 2)) {
				c++;
			}
			else if (sizes.get(i) < (avgSize * 3)) {
				d++;
			}
			else if (sizes.get(i) < (avgSize * 4)) {
				e++;
			}
			else {
				f++;
			}
			
		}
		
		// print
		System.out.println("There are " + sizes.getSize() + " subgraphs.");
		System.out.println("The sum of their sizes is " + sum);
		System.out.println("The max size is " + max);
		System.out.println("The min size is " + min);
		System.out.println("The average size is " + avgSize);
//		System.out.println("The size of 10%-large subgraph is " + sizes.get((int) Math.round(0.1 * sizes.getSize())));
		System.out.println("The new theoretic 2-radius subgraph size is " + newTheoSize);
		System.out.println("There are " + g + " subgraphs of 1/8 smaller size than average.");
		System.out.println("There are " + h + " subgraphs of 1/4 smaller size than average.");
		System.out.println("There are " + a + " subgraphs of half smaller size than average.");
		System.out.println("There are " + b + " subgraphs of smaller size than average.");
		System.out.println("There are " + c + " subgraphs of larger size than average.");
		System.out.println("There are " + d + " subgraphs of twice larger size than average.");
		System.out.println("There are " + e + " subgraphs of third larger size than average.");
		System.out.println("There are " + f + " subgraphs of four larger size than average.");
	}
	
	public void statDataGraph(int n, int m) {
		this.n = n;
		this.m = m;
		
		// statistic
		double avgDegree = (double) m / (double) n;
		theoSize = 1.0D + avgDegree + Math.pow(avgDegree, 2);
		double extTheoSize = 1.0D + 2 * avgDegree + Math.pow(2 * avgDegree, 2);
		
		// print
		System.out.println("There are " + n + " vertexes.");
		System.out.println("There are " + m + " edges.");
		System.out.println("The average degree is " + avgDegree);
		System.out.println("The theoretic 2-radius subgraph size is " + theoSize);
		System.out.println("The extended theoretic 2-radius subgraph size is " + extTheoSize);
		System.out.println();
	}
}
